using System.Collections.Generic;
using BitBenderGames;
using Unity.Mathematics;
using UnityEngine;
using WorldMapBase.Layer;
using WorldMapBase.LOD;
using WorldMapBase.Tile.Pool;
using Yoozoo.Gta.Common;
using Yoozoo.Libs;
using Yoozoo.Managers;

namespace WorldMapBase.Tile
{
    public class TileDisplayManager
    {
        private const int MAX_TILE_PROCESS_NUM = 30;
        private const int MAX_PER_FRAME_CONSUME_TIME = 1;

        private const int DelayFrame = 5;
        private int currentFrame = 0;

        private readonly System.Diagnostics.Stopwatch m_Stopwatch = new System.Diagnostics.Stopwatch();

        private List<int> layerIDs;

        private Dictionary<int, LODStrategy> LODStrategies;    // 物件层级ID 对应 LOD策略
        private Dictionary<int, LODTileLayerListener> LODTileLayerListeners; // 物件层级ID 对应 LOD地块监听
        private Dictionary<int, ILayerContainerStrategy> LayerContainerStrategies; // 物件层级ID 对应LOD容器策略
        private Dictionary<int, Dictionary<int, TileLayer>> TileLayers;    // 保留对TileLayer的引用

        private HashSet<long> ShowingTile; // 陆地显示
        private HashSet<long> ShowingOverSeaTile; // 海外显示
        
        private Dictionary<int, int4> ViewRectPreFrame;

        private LinkedList<TileCommandBase> m_CommandList;     // 命令列表

        private LinkedList<TileCommandBase> m_CommandCacheList;

        private bool m_isPause;
        private bool m_TweenMoving;
        private bool m_ForceLoad; // 强制加载状态
        public bool TweenMoving => m_TweenMoving;
        public bool bForceLoad => m_ForceLoad;
        private static TileDisplayManager instance;
        public static TileDisplayManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new TileDisplayManager();
                }
                return instance;
            }
        }

        private TileDisplayManager()
        {
            m_isPause = true;

            // ClassManager.Store<TileShowCmd>(500);
            // ClassManager.Store<TileHideCmd>(500);

            layerIDs = new List<int>();

            ShowingTile = new HashSet<long>();
            ShowingOverSeaTile = new HashSet<long>();
            LODStrategies = new Dictionary<int, LODStrategy>();
            LODTileLayerListeners = new Dictionary<int, LODTileLayerListener>();
            LayerContainerStrategies = new Dictionary<int, ILayerContainerStrategy>();
            ViewRectPreFrame = new Dictionary<int, int4>();
            TileLayers = new Dictionary<int, Dictionary<int, TileLayer>>();
            m_CommandList = new LinkedList<TileCommandBase>();
            m_CommandCacheList = new LinkedList<TileCommandBase>();
        }

        public void Clear()
        {
            if (_touchCameraController)
            {
                var mc = _touchCameraController.GetCameraComponet<CameraMoveComponent>();
                if (mc)
                {
                    mc.onBeginMove -= OnCameraBeginMove;
                    mc.onEndMove -= OnCameraEndMove;
                }
            }

            layerIDs.Clear();
            ShowingTile.Clear();
            ShowingOverSeaTile.Clear();
            LODStrategies.Clear();
            LayerContainerStrategies.Clear();
            ViewRectPreFrame.Clear();
            foreach (var pair in LODTileLayerListeners)
            {
                var listener = pair.Value;
                listener.Dispose();
            }
            LODTileLayerListeners.Clear();
            TileLayers.Clear();
            m_CommandList.Clear();
            m_CommandCacheList.Clear();
            // 切换场景 清除出生点数据
            LODTileLayerListener layerListener = TileDisplayManager.Instance.GetTileLayerListener(WorldEntry.MAP_POINT_ID);
            if (layerListener != null) layerListener.ClearMapPointState();

        }

        private void OnCameraBeginMove()
        {
            SetTweenMoveStatus(true);
        }

        private void OnCameraEndMove()
        {
            SetTweenMoveStatus(false);
        }

#if UNITY_EDITOR
        private static int debugFrame = 0;
        public static int TreeNum = 0;
        public static int MountainNum = 0;

        public static int TileNum = 0;
        public static bool shouldShowDebug = true;

        public static void OnShowElement(int resID)
        {
            // if (WorldMapConfigData.TreeResIDS.Contains(resID))
            // {
            //     TreeNum++;
            // }
            // else if (WorldMapConfigData.MountainResIDs.Contains(resID))
            // {
            //     MountainNum++;
            // }
            shouldShowDebug = true;
        }

        public static void OnHideElement(int resID)
        {
            // if (WorldMapConfigData.TreeResIDS.Contains(resID))
            // {
            //     TreeNum--;
            // }
            // else if (WorldMapConfigData.MountainResIDs.Contains(resID))
            // {
            //     MountainNum--;
            // }
            shouldShowDebug = true;
        }

        public void ShowDebugInfo()
        {
            if (!DebugSetting.ShowObjectNumLog)
            {
                return;
            }

            string log = string.Format(
                @"【Editor】[沙盘物体数量][静态物体]
                地块 数量: {0}
                树木 数量: {1}
                山体 数量: {2}
", TileNum / 4, TreeNum, MountainNum);

            UnityEngine.Debug.Log(log);
        }

#endif

        private TouchCameraController _touchCameraController;

        public void OnUpdate()
        {
#if UNITY_EDITOR
            debugFrame++;
            if (debugFrame > 60)
            {
                if (shouldShowDebug)
                {
                    ShowDebugInfo();
                    shouldShowDebug = false;
                }
                debugFrame = 0;
            }
#endif
            if (_touchCameraController == null && WorldCameraManager.cameraController != null)
            {
                _touchCameraController = WorldCameraManager.cameraController;
                var mc = _touchCameraController.GetCameraComponet<CameraMoveComponent>();
                if (mc)
                {
                    mc.onBeginMove += OnCameraBeginMove;
                    mc.onEndMove += OnCameraEndMove;
                }
            }

            if (!m_ForceLoad)
            {
                if (m_isPause)
                {
                    return;
                }
            }

            currentFrame++;
            if (currentFrame > DelayFrame)
            {
                // 淦 TODO 需要自己实现链表类，C# Next属性没有set
                //m_CommandList.Last.Next = m_CommandCacheList.First;
            }


            foreach (var layerID in layerIDs)
            {
                // 更新各个层级的视图范围
                int4 viewRect = LayerContainerStrategies[layerID].GetViewRect();

                ViewRectPreFrame[layerID] = viewRect;
            }

            m_Stopwatch.Reset();
            m_Stopwatch.Start();

            int processNum = 0;

            while (m_CommandList.Count > 0 && m_Stopwatch.ElapsedMilliseconds < MAX_PER_FRAME_CONSUME_TIME && processNum < MAX_TILE_PROCESS_NUM)
            {
                if (m_CommandList.First.Value.Check())
                {
                    m_CommandList.First.Value.Execute();
                    processNum++;
                }
                m_CommandList.First.Value.Recover();
                //ClassManager.Free((IClass)m_CommandList.First.Value);

                ClassPoolManager.RecoverTileCommandNode(m_CommandList.First);
                m_CommandList.RemoveFirst();
            }

            m_Stopwatch.Stop();
        }


        public void SetPauseStatus(bool p)
        {
            m_isPause = p;
        }

        public void SetForceLoad(bool value)
        {
            m_ForceLoad = value;
        }

        public void SetTweenMoveStatus(bool status)
        {
            m_TweenMoving = status;
            if (!status)
            {
                OnViewRectForce();
            }
            else
            {
                OnViewRectJumpBegin();
            }
        }

        private void OnViewRectJumpBegin()
        {
            foreach (var layerID in layerIDs)
            {
                // 更新各层级视图范围
                int4 viewRect = LayerContainerStrategies[layerID].GetViewRect();
                // 获取各层级LOD等级
                int lodLevel = LODStrategies[layerID].GetLODLevel();
                // 设置TileLayer的上次视口范围
                if (TileLayers[layerID].ContainsKey(lodLevel)) TileLayers[layerID][lodLevel].SetLastViewRect(viewRect);
            }

        }

        public void OnViewRectForce()
        {
            foreach (var layerID in layerIDs)
            {
                // 更新各层级视图范围
                int4 viewRect = LayerContainerStrategies[layerID].GetViewRect();
                int lodLevel = LODStrategies[layerID].GetLODLevel();
                // 这里需要去访问真实打开的各层级的LODLayerContainer
                LayerContainer layerContainer = DynamicLayerMgr.worldEntry.GetLayerContainer(layerID);
                if (layerContainer != null)
                {
                    LODLayerContainer lodContainer = layerContainer as LODLayerContainer;
                    if (lodContainer != null) lodLevel = lodContainer.GetLodLevel(lodLevel);
                }
                if (TileLayers[layerID].ContainsKey(lodLevel))
                {
                    TileLayers[layerID][lodLevel].forceUpdateViewRect = true;
                    TileLayers[layerID][lodLevel].UpdateViewForce(viewRect);
                }
            }
        }

        public void AddShowCommand(int layerID, int lodLevel, int tileIndex, int2 worldPos)
        {
            TileShowCmd showCmd = ClassPoolManager.GetTileShowCmd();
            showCmd.Init(layerID, lodLevel, tileIndex, worldPos);

            var node = ClassPoolManager.GetTileCommandNode();
            node.Value = showCmd;
            // 如果是地表的显示命令 直接执行
            if (layerID == WorldEntry.PLANE_LAYER_ID)
            {
                showCmd.Execute();
                showCmd.Recover();
            }
            else
            {
                m_CommandList.AddLast(node);
            }
            //m_CommandCacheList.AddLast(showCmd);
        }

        public void AddHideCommand(int layerID, int lodLevel, int tileIndex)
        {
            TileHideCmd hideCmd = ClassPoolManager.GetTileHideCmd();
            hideCmd.Init(layerID, lodLevel, tileIndex);

            var node = ClassPoolManager.GetTileCommandNode();
            node.Value = hideCmd;

            // 如果是地表的隐藏命令 直接执行
            if (layerID == WorldEntry.PLANE_LAYER_ID)
            {
                hideCmd.Execute();
                hideCmd.Recover();
            }
            else
            {
                m_CommandList.AddLast(node);
            }

            //m_CommandCacheList.AddLast(hideCmd);
        }

        public void AddLodStrategy(int layerID, LODStrategy lodStrategy)
        {
            LODStrategies[layerID] = lodStrategy;
        }

        public void AddTileLayer(int layerID, int levelID, TileLayer layer)
        {
            Dictionary<int, TileLayer> tileLayers;
            if (!TileLayers.TryGetValue(layerID, out tileLayers))
            {
                tileLayers = new Dictionary<int, TileLayer>();
                TileLayers[layerID] = tileLayers;
            }

            tileLayers[levelID] = layer;
        }

        // 获取层级的Lod等级
        public int GetLayerLODLevel(int layerID)
        {
            LODStrategy lodStrategy;
            if (LODStrategies.TryGetValue(layerID, out lodStrategy))
            {
                return lodStrategy.GetLODLevel();
            }

            return -1;
        }

        private int2 lbTileXY = new int2();
        private int2 rtTileXY = new int2();

        public bool TileInRect(int layerID, int lodLevel, int tileIndex)
        {
            // 检测地块是否在视野范围内
            int4 viewRect = ViewRectPreFrame[layerID];
            Vector2Int grid = WorldMapConfigData.GetTileGridByIndex(layerID, lodLevel, tileIndex);

            TileLayers[layerID][lodLevel].GetTileGridRange(viewRect, out lbTileXY, out rtTileXY);

            if (grid.x < lbTileXY.x || grid.x > rtTileXY.x || grid.y < lbTileXY.y || grid.y > rtTileXY.y)
            {
                return false;
            }
            return true;
        }

        public void AddTileLayerListener(int layerID, LODTileLayerListener lodTileLayerListener)
        {
            LODTileLayerListeners[layerID] = lodTileLayerListener;
        }

        public LODTileLayerListener GetTileLayerListener(int layerID)
        {
            LODTileLayerListener lodTileLayerListener = null;
            LODTileLayerListeners.TryGetValue(layerID, out lodTileLayerListener);
            return lodTileLayerListener;
        }

        private long GetTileCode(int layerID, int lodLevel, int tileIndex)
        {
            // 注意 这里的tileIndex  可能是在海外的 
            return (tileIndex * 100 + layerID) * 100 + lodLevel;
        }

        public bool EdgeTileIsShowing(int layerID, int lodLevel, int tileIndex)
        {
            return ShowingOverSeaTile.Contains(GetTileCode(layerID, lodLevel, tileIndex));
        }

        // 地块是否在显示状态
        public bool TileIsShowing(int layerID,int lodLevel, int tileIndex)
        {
            return ShowingTile.Contains(GetTileCode(layerID,lodLevel, tileIndex));
        }
        
        
        public void OnAddTile(TileShowCmd showCmd)
        {
            LODTileLayerListener layerListener = GetTileLayerListener(showCmd.LayerID);
            if (layerListener != null)
            {
                ShowingTile.Add(GetTileCode(showCmd.LayerID, showCmd.LodLevel, showCmd.TileIndex));
                layerListener.OnAddTile(showCmd.LodLevel, showCmd.TileIndex,showCmd.WorldCenterPos);
            }
        }

        public void OnRemoveTile(TileHideCmd hideCmd)
        {
            LODTileLayerListener layerListener = GetTileLayerListener(hideCmd.LayerID);
            if (layerListener!=null)
            {
                ShowingTile.Remove(GetTileCode(hideCmd.LayerID, hideCmd.LodIndex, hideCmd.TileIndex));

                layerListener.OnRemoveTile(hideCmd.LodIndex,hideCmd.TileIndex);
            }
        }

        public void AddLayerContainer(int LayerID, ILayerContainerStrategy containerStrategy)
        {
            layerIDs.Add(LayerID);
            LayerContainerStrategies[LayerID] = containerStrategy;
        }
    }
}